/*
 * lib/httpreq.c
 * http请求处理模块 V 0.1
 * 作者:cgc insharecgc@gmail.com
 */
 
#include "../include/httpreq.h"

void
httpreq(struct clientinfo ci)
{
	char recv_buf[RECV_BUFFER_SIZE + 1];		/* 服务器端通过网络套接字接受到的信息 */
	char send_buf[SEND_BUFFER_SIZE + 1];		/* 服务器端通过网络套接字发送的信息 */
	char uri_buf[URI_SIZE + 1];					/* 客户端请求的uri地址 */
	char file_buf[FILE_MAX_SIZE + 1];			/* 服务器端返回给客户端的显示内容 */
	int file_size = 0;
	int read_bytes = 0, send_bytes = 0;
	char method[4];
		
	int maxfd = ci->confd + 1;
	fd_set read_set;
	FD_ZERO(&read_set);
	struct timeval timeout;
	timeout.tv_sec = TIME_OUT_SEC;
	timeout.tv_usec = TIME_OUT_USEC;	
	int flag = 1, res = 0;	
	FD_SET(ci->confd, &read_set);
	while(flag)
	{		
		res = select(maxfd, &read_set, NULL, NULL, &timeout);
		switch(res)
		{
			case -1:		/* 出错 */
				//syslog(, "\n");
				close(ci->confd);
				return;
			case 0:			/* 超时 */
				continue;
				break;
			default:		/* 有动作 */
				if(FD_ISSET(ci->confd, &read_set))
				{
			  		flag=0;
					memset(recv_buf, '\0', sizeof(recv_buf));
					if((read_bytes = recv(ci->confd, recv_buf, RECV_BUFFER_SIZE, 0)) == 0)
					{
						/* 客户端已关闭连接  */
						return 0;
					}				
					else if(read_bytes > 0)		
					{
						if(is_http_protocol(recv_buf) < 0)	 /* 判断是否是http请求 */
						{
							//syslog(, "监听的端口号不是通过http协议请求过来的\n");
							close(ci->confd);
							return -1;
						}
						else		/* http请求 */
						{
							strncpy(method,recv_buf,4);
							memset(file_buf,  '\0', sizeof(file_buf));
							memset(send_buf, '\0', sizeof(send_buf));
							memset(uri_buf, '\0', sizeof(uri_buf));						
							get_uri(recv_buf, uri_buf);
							
							if(strcasecmp(method,"post") == 0){		/* post请求 */	
								if(do_post_request(recv_buf， file_buf) < 0){
									//syslog(, "无效的post请求，httpreq().\n");
									return -1;						
								}
								file_size=strlen(file_buf);
							}
							else		/* get请求 */
							{							
								if(strcmp(uri_buf, "index.html") == 0)		/* 客户默认请求，这里需要提取index.txt模板 */	
									httpclireq(ci, file_buf);		/* 直接将客户端信息保存的地址传下去 */
									file_size=strlen(file_buf);
								
								else		/* 直接请求其他html文件 */
									file_size =  get_file_disk(uri_buf, file_buf);
							}
							send_bytes = reply_normal_information(send_buf, file_buf, file_size, "text/html");
							send(ci->confd, send_buf, send_bytes, 0);	
						}
					}
				}
			}
	}
	return 0;
}

/*
 * 描述: 判断是否是HTTP协议
 * msg_from_client: 从客户端来自的连接信息
 * 返回: 0成功;  -1失败
 */
int 
is_http_protocol(char *msg_from_client)
{
	int index = 0;
	while(msg_from_client[index] != '\0' && msg_from_client[index] != '\n')
		index++;
	if(strncmp(msg_from_client + index - 9, "HTTP/", 5) == 0)
		return 0;
		
	return -1;
}

/*
 * 描述: 处理POST请求
 * recv_buf: HTTP的POST请求
 * file_buf: 显示给客户端的内容
 * 返回: 0成功;  -1失败 
 */
int
do_post_request(char *recv_buf, char *file_buf)
{
	char *post_entity;						/* 用于保存HTTP请求头中的主题 */	
	post_entity = get_post_entity(recv_buf);
	
	if(strcmp(uri_buf, "apply.html") == 0)		/* 处理POST请求,客户要求使用usb */
		usb_apply(post_entity, file_buf);
		
	else if(strcmp(uri_buf, "adminlogin.html") == 0)/* 处理POST请求，管理员登录 */
		admin_login(post_entity, file_buf);
		
	else if(strcmp(uri_buf, "admin.html") == 0)	/* 用于已经登录成功后管理员的操作 */
		admin_control(post_entity, file_buf);
	
	else				/* 无效的请求 */
		return -1;
		
	return 0;				
}

/*
 * 描述: 得到POST请求的实体部分
 * recv_buf: HTTP请求头内容
 * 返回: 返回HTTP请求头中的实体内容 成功;  NULL 失败
 */
char*
get_post_entity(char *recv_buf)
{
	int index1=0,index2=0;
	char *post_entity;
		
	while(recv_buf[index1] != '\0')
		index1++;
		
	index2=index1;
	
	while(recv_buf[index2] != '\n')
		index2--;
	
	post_entity = str_cpy_from_to(recv_buf, index2+1, index1);	
	return post_entity;
}

/*
 * 描述: 拷贝字符串函数
 * src: 是原字符串
 * from: 是需要拷贝的第一个字符位置
 * end: 为最后一个拷贝字符位置
 * 返回: 拷贝成功的字符 成功;  NULL 失败
 */
char*
str_cpy_from_to(char *src, int from, int end)
{
	int index=0;
	char *dest;
	if((dest = malloc(POST_ENTITY_SIZE * sizeof(char))) == NULL){
		//syslog(, "分配内存失败，httpreq.c for str_cpy_from_to()\n");
		return NULL;
	}
	while(from <= end)
	{
		dest[index++] = src[from++];
	}
	dest[index]='\0';
	
	return dest;
}

/*
 * 描述： 把template_txtfile文件里的内容读入到template_buf中
 * template_txtfile: 模板文件的路径以及名字
 * template_buf: 存放模板文件中的内容
 * 返回: 模板文件内容的长度 成功;   -1失败
 */
int 
get_template_txtfile(char *template_txtfile, char *template_buf)
{
	int fd, size;
	
	if((fd = open(template_txtfile, O_RDONLY)) == -1){
		//syslog(, "打开模板文件错误, where httpreq.c for get_template_txtfile().\n");
		return -1;
	}
	
	if((size = read(fd, template_buf, sizeof(template_buf))) < 0){
		//syslog(, "读取模板文件错误, where httpreq.c for get_template_txtfile().");
		return -1;
	}
	return size;
}

/* 
 * 描述: 根据请求的头信息,取得http请求的uri 
 * req_header: 客户请求内容
 * uri_buf: 用于保存获得的uri
 */
void
get_uri(char *req_header, char *uri_buf)
{
	int index = 0;
	while( (req_header[index] != '/') && (req_header[index] != '\0') )
	{
		index++;
	}
	int base = index;
	while( ((index - base) < URI_SIZE) && (req_header[index] != ' ') && (req_header[index] != '\0') )
	{
		index++;
	}
	if((req_header[index - 1] == '/') && (req_header[index] == ' '))
	{
		strcpy(uri_buf, "index.html");
		return;
	}
	strncpy(uri_buf, req_header + base + 1, index - base - 1);
	
	return ;

}

/* 描述: 取得GET请求的本地uri,把内容放到file_buf中 */
int 
get_file_disk(char *uri, char *file_buf)
{
	char *real_uri;
	if((uri = malloc(URI_SIZE * sizeof(char))) == NULL){
		//syslog(, "分配内存空间错误，httpreq.c for get_file_disk().\n");
		return -1;
	}
	strcpy(real_uri, "./varusbctrl/template/");
	strcat(real_uri, uri);
	int read_count = 0;
	int fd = open(real_uri, O_RDONLY);
	free(real_uri);		/* 释放内存空间 */
	if(fd == -1)
	{
		//syslog(, "以只读方式打开请求文件失败，httpreq.c for get_file_disk().\n");
		return -1;
	}
	unsigned long st_size;
	struct stat st; 			/* 用于获得请求的文件的状态 */
	if(fstat(fd, &st) == -1)
	{
		//syslog(, "获取请求文件状态失败，httpreq.c for get_file_disk().\n");
		return -1;
	}
	st_size = st.st_size;
	if(st_size > FILE_MAX_SIZE)
	{
		//syslog(, "请求的内容大于最大请求内容，httpreq.c for get_file_disk().\n");
		return -1;
	}
	if((read_count = read(fd, file_buf, FILE_MAX_SIZE)) == -1)
	{
		//syslog(, "读取请求文件中的内容错误，httpreq.c for get_file_disk().\n");
		return -1;
	}
	return read_count;
}

/* 描述: 把file_buf中的内容添加http相应头 */
int 
reply_normal_information(char *send_buf, char *file_buf, int file_size,  char *mime_type)
{
	char *str =  "HTTP/1.1 200 OK\r\nServer:web server for usbctrol(1.0)\r\nDate:";
	register int index = strlen(str);
	memcpy(send_buf, str, index);

	char time_buf[TIME_BUFFER_SIZE];
	memset(time_buf, '\0', sizeof(time_buf));
	str = get_time_str(time_buf);
	
	int len = strlen(time_buf);
	memcpy(send_buf + index, time_buf, len);
	index += len;

	len = strlen(ALLOW);
	memcpy(send_buf + index, ALLOW, len);
	index += len;

	memcpy(send_buf + index, "\r\nContent-Type:", 15);
	index += 15;
	
	memcpy(send_buf + index, "text/html", 9);
	index += 9;

	memcpy(send_buf + index, "\r\nContent-Length:", 17);
	index += 17;
	
	char num_len[8];
	memset(num_len, '\0', sizeof(num_len));
	sprintf(num_len, "%d", file_size);   /*格式化num_len把file_size的值赋给num_len*/
	len = strlen(num_len);
	memcpy(send_buf + index, num_len, len);
	index += len;

	memcpy(send_buf + index, "\r\n\r\n", 4);
	index += 4;
	
	memcpy(send_buf + index, file_buf, file_size);
	index += file_size;
	return index;
}





